/*
 ************************************************************************************************
 *                                                                                              *
 *  OSA cooperative RTOS for Microchip PIC-controllers: PIC10/12/16/18/24/dsPIC                 *
 *                                                                                              *
 *  URL:            http://wiki.pic24.ru/doku.php/en/osa/ref/intro                              *
 *                  http://picosa.narod.ru                                                      *
 *                                                                                              *
 *----------------------------------------------------------------------------------------------*
 *                                                                                              *
 *  File:           osa_picc12.h                                                                *
 *                                                                                              *
 *  Compilers:      HT-PICC STD                                                                 *
 *                  HT-PICC18 STD                                                               *
 *                  Microchip C18                                                               *
 *                  Microchip C30                                                               *
 *                                                                                              *
 *  Programmer:     Timofeev Victor                                                             *
 *                  osa@pic24.ru, testerplus@mail.ru                                            *
 *                                                                                              *
 *  Description:    PICC12 specific definitions                                                 *
 *                                                                                              *
 *                                                                                              *
 ************************************************************************************************
 */



#ifndef __OSAPICC12_H__
#define __OSAPICC12_H__





asm("   psect os_pic12_jmp_table,ovrld,global,class=ENTRY,delta=2   ");
asm("_os_pic12_jmp_table:                                           ");




/************************************************************************************************
 *                                                                                              *
 *     Registers definitions                                                                    *
 *                                                                                              *
 ************************************************************************************************/

static volatile char _indf @ 0x0;
static volatile char _pcl @ 0x02;
static volatile char _fsr @ 0x4;
static volatile char _status @ 0x3;





/************************************************************************************************
 *                                                                                              *
 *     Constants and types                                                                      *
 *                                                                                              *
 ************************************************************************************************/

#undef OS_SMSG_SIZE
#define OS_SMSG_SIZE    sizeof(OS_SMSG_TYPE)

//------------------------------------------------------------------------------

#if defined(OS_ENABLE_QUEUE) || defined(OS_ENABLE_SQUEUE)
    #define OS_ENABLE_QUEUE
    #undef  OS_ENABLE_SQUEUE
    #define OS_QUEUE_SQUEUE_IDENTICAL
#endif

//------------------------------------------------------------------------------

typedef unsigned char              _FSR_TYPE;
typedef unsigned char               OST_CODE_POINTER;









/************************************************************************************************
 *                                                                                              *
 *     Platform macros                                                                          *
 *                                                                                              *
 ************************************************************************************************/

#define _PIC18_ERRATA_NOP()     // Empty macro for this type of PICs

#define OS_CLRWDT()   asm(" clrwdt ");
#define OS_ClrWdt()   asm(" clrwdt ");
#define OS_SLEEP()    asm(" sleep  ");









/************************************************************************************************
 *                                                                                              *
 *     Context switching macros                                                                 *
 *                                                                                              *
 ************************************************************************************************/


#if !defined   (_BANKBITS_)
    #define     _BANKBITS_  2
#endif




//------------------------------------------------------------------------------
// Macros for setting task descriptor's bank
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
#if     OS_BANK_TASKS == 0
//------------------------------------------------------------------------------

    #define _OS_SET_TASK_IRP()
    #define _OS_SET_TASK_IRP_0()

//------------------------------------------------------------------------------
#elif   OS_BANK_TASKS == 1
//------------------------------------------------------------------------------

    #define _OS_SET_TASK_IRP()      asm("   bsf     __fsr, 5 ");
    #define _OS_SET_TASK_IRP_0()    asm("   bcf     __fsr, 5 ");

//------------------------------------------------------------------------------
#elif   OS_BANK_TASKS == 2
//------------------------------------------------------------------------------

    #define _OS_SET_TASK_IRP()      asm("   bsf     __fsr, 6 ");
    #define _OS_SET_TASK_IRP_0()    asm("   bcf     __fsr, 6 ");

//------------------------------------------------------------------------------
#elif   OS_BANK_TASKS == 3
//------------------------------------------------------------------------------

    #define _OS_SET_TASK_IRP()      asm("   bsf     __fsr, 5 ");    \
                                    asm("   bsf     __fsr, 6 ");

    #define _OS_SET_TASK_IRP_0()    asm("   bcf     __fsr, 5 ");    \
                                    asm("   bcf     __fsr, 6 ");

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------




//------------------------------------------------------------------------------
// Macros for setting OS variables bank
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
#if     OS_BANK_OS == 0
//------------------------------------------------------------------------------

    #define _OS_SET_OS_IRP()
    #define _OS_SET_OS_IRP_0()

//------------------------------------------------------------------------------
#elif   OS_BANK_OS == 1
//------------------------------------------------------------------------------

    #define _OS_SET_OS_IRP()    asm("   bsf     __fsr, 5 ");
    #define _OS_SET_OS_IRP_0()  asm("   bcf     __fsr, 5 ");

//------------------------------------------------------------------------------
#elif   OS_BANK_OS == 2
//------------------------------------------------------------------------------

    #define _OS_SET_OS_IRP()    asm("   bsf     __fsr, 6 ");
    #define _OS_SET_OS_IRP_0()  asm("   bcf     __fsr, 6 ");

//------------------------------------------------------------------------------
#elif   OS_BANK_OS == 3
//------------------------------------------------------------------------------

    #define _OS_SET_OS_IRP()    asm("   bsf     __fsr, 5 ");    \
                                asm("   bsf     __fsr, 6 ");

    #define _OS_SET_OS_IRP_0()  asm("   bcf     __fsr, 5 ");    \
                                asm("   bcf     __fsr, 6 ");

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------







//------------------------------------------------------------------------------
#if _BANKBITS_ == 0
    #define _OS_PIC12_AND_1F()
#endif

//------------------------------------------------------------------------------
#if _BANKBITS_ == 1
    #define _OS_PIC12_AND_1F()  asm("   andlw   0x1F    ");
#endif

//------------------------------------------------------------------------------
#if _BANKBITS_ == 2
    #define _OS_PIC12_AND_1F()  asm("   andlw   0x1F    ");
#endif


//------------------------------------------------------------------------------



#define OS_SET_PAGE_ADDR0()                                     \
    asm("   global _os_pic12_jmp_table      ");                 \
    asm("   dw  0x4A3   | ((_os_pic12_jmp_table & 0x200)>>1)");


#define OS_SET_PAGE_ADDR1()                                     \
    asm("   global _os_pic12_jmp_table      ");                 \
    asm("   dw  0x4C3   | ((_os_pic12_jmp_table & 0x400)>>2)");


//------------------------------------------------------------------------------


/*
 ********************************************************************************
 *                                                                              *
 *  _OS_JumpToTask()                                                            *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:        jump indirectly from kernel (OS_Sched) into task        *
 *                                                                              *
 ********************************************************************************
 */

#define _OS_JumpToTask()                                                    \
    {                                                                       \
        _fsr = ((_FSR_TYPE)_OS_CurTask);                                    \
        asm("   movf    __indf, w    ");                                    \
        _OS_SET_TASK_IRP_0();                                               \
        asm("   movwf   _OS_state   ");                                     \
        _fsr = ((_FSR_TYPE)_OS_CurTask) + 1;                                \
        asm("   movf    __indf, w    ");                                    \
        asm("   global  OS_JumpToTask_W    ");                              \
        asm("OS_JumpToTask_W:       ");                                     \
        asm("   clrf    __fsr       ");                                     \
        OS_SET_PAGE_ADDR0();                                                \
        OS_SET_PAGE_ADDR1();                                                \
        asm("   movwf   __pcl        ");                                    \
    }


//------------------------------------------------------------------------------






/*
 ********************************************************************************
 *                                                                              *
 *  _OS_SaveRetAddr()                                                           *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:    Save task return address.                                   *
 *                                                                              *
 *  parameters:     WREG    - address low byte                                  *
 *                                                                              *
 ********************************************************************************
 */

#define _OS_SaveRetAddr()                                                               \
{                                                                                       \
    asm("global  OS_SchedRetPoint   ");                                                 \
    asm("global  OS_SchedRetPoint3   ");                                                \
    asm("global  OS_ClearReady  ");                                                     \
    asm("global  OS_ClearReadySetCanContinue  ");                                       \
    asm("global  OS_JumpToTask_W    ");                                                 \
                                                                                        \
    asm("OS_ClearReadySetCanContinue:  ");                                              \
    asm("OS_ClearReady:  ");                                                            \
    asm("   bcf   _OS_state, 3      ");       /* bReady = 0 */                          \
    asm("   bsf   __status, 1        ");      /* =1 - we need to return to task */      \
    asm("   btfss __status, 1        ");                                                \
    asm("OS_SchedRetPoint:   ");                                                        \
    asm("   bcf   __status, 1    ");          /* =0 - we don't need to return to task */\
                                                                                        \
    /* Now FSR = 0, W = task return point */                                            \
                                                                                        \
    asm("   movwf   __OS_temp     ");                                                   \
    asm("   incf    __OS_CurTask, w ");                                                 \
    _OS_PIC12_AND_1F();                                                                 \
    asm("   movwf   __fsr    ");                                                        \
    asm("   movf    __OS_temp, w");                                                     \
    _OS_SET_TASK_IRP();                                                                 \
    asm("   movwf   __indf   ");                                                        \
    _OS_SET_TASK_IRP_0();                                                               \
    asm("   btfsc   __status, 1 ");                                                     \
    asm("   goto    OS_JumpToTask_W ");                                                 \
    asm("OS_SchedRetPoint3:      ");                                                    \
                                                                                        \
    /* Save state      */                                                               \
                                                                                        \
    asm("   movf    __OS_CurTask, w");                                                  \
    _OS_PIC12_AND_1F();                                                                 \
    asm("   movwf   __fsr   ");                                                         \
    asm("   movf    _OS_state, w");                                                     \
    asm("   andlw   0x38    ");             /* bReady, bCanContinue and             */  \
                                            /* !!!bDelay!!! (!!! - only for PICC12) */  \
    _OS_SET_TASK_IRP();                                                                 \
    asm("   bcf     __indf, 3");            /* bReady */                                \
    asm("   bcf     __indf, 4");            /* bDelay */                                \
    asm("   bcf     __indf, 5");            /* bCanContinue */                          \
    asm("   iorwf   __indf, f");                                                        \
    _OS_SET_TASK_IRP_0();                                                               \
}

//------------------------------------------------------------------------------








/************************************************************************************************
 *                                                                                              *
 *     Return from task to OS_Sched macros                                                      *
 *                                                                                              *
 ************************************************************************************************/


/*
 ********************************************************************************
 *                                                                              *
 *   Switch control routines:                                                   *
 *                                                                              *
 *    _OS_GetReturnPoint()                - exit from task and save context     *
 *                                                                              *
 *    _OS_ReturnNoSave()                  - exit withowt saving return address  *
 *                                                                              *
 *    _OS_CLEAR_READY()                   - exit with saving address and        *
 *                                          clearing bReady                     *
 *                                                                              *
 *    _OS_CLEAR_READY_SET_CANCONTINUE()   - exit without saving address and     *
 *                                          clearing bReady and bCanContinue    *
 *                                                                              *
 ********************************************************************************
 */


#define _OS_GetReturnPoint()    {                                               \
                                    OS_state.bReady = 1;                        \
                                    asm(" _goto_OS_SchedRetPoint ");            \
                                }                                               \

#define _OS_ReturnNoSave()          asm(" _goto_OS_SchedRetPoint3 ");

#define _OS_CLEAR_READY()       {                                               \
                                    OS_state.bCanContinue = 0;                  \
                                    asm(" _call_OS_ClearReady ");               \
                                }                                               \

#define _OS_CLEAR_READY_SET_CANCONTINUE()                                       \
                                {                                               \
                                    OS_state.bCanContinue = 1;                  \
                                    asm(" _call_OS_ClearReadySetCanContinue "); \
                                }                                               \

//------------------------------------------------------------------------------

#define _OS_SET_FSR_CUR_TASK_W()
#define _OS_SET_FSR_CUR_TASK()

//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
/************************************************************************/
/* Add task address in jump table                                       */
/************************************************************************/
    asm("_OS_Add_TaskAddr               macro   TaskAddr");
    asm("   local   label2                              ");
    asm("                                               ");
    asm("   movlw   low(label2)                         ");
    asm("   movwf   __OS_temp                           ");
    asm("   psect   os_pic12_jmp_table                  ");
    asm("                                               ");
    asm("label2:                                        ");
    asm("   ljmp    TaskAddr                            ");
    asm("                                               ");
    asm("   endm                                        ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Exit task and save context                                           */
/************************************************************************/
    asm("_goto_OS_SchedRetPoint         macro           ");
    asm("                                               ");
    asm("   local   task_ret_point, label2              ");
    asm("   global  OS_SchedRetPoint                    ");
    asm("                                               ");
    asm("   dw      0xC00 | low(label2)                 ");
    asm("   ljmp    OS_SchedRetPoint                    ");
    asm("                                               ");
    asm("task_ret_point:                                ");
    asm("   psect   os_pic12_jmp_table                  ");
    asm("                                               ");
    asm("label2:                                        ");
    asm("   ljmp    task_ret_point                      ");
    asm("                                               ");
    asm("   endm                                        ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Exit task without saving context                                     */
/************************************************************************/
    asm("_goto_OS_SchedRetPoint3        macro           ");
    asm("                                               ");
    asm("   global  OS_SchedRetPoint3                   ");
    asm("                                               ");
    asm("   ljmp    OS_SchedRetPoint3                   ");
    asm("                                               ");
    asm("   endm                                        ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Save context with clearing bReady flag                               */
/************************************************************************/
    asm("_call_OS_ClearReady            macro           ");
    asm("                                               ");
    asm("   local   task_ret_point, label2              ");
    asm("   global  OS_ClearReady                       ");
    asm("                                               ");
    asm("   dw      0xC00 | low(label2)                 ");
    asm("   ljmp    OS_ClearReady                       ");
    asm("                                               ");
    asm("task_ret_point:                                ");
    asm("   psect   os_pic12_jmp_table                  ");
    asm("                                               ");
    asm("label2:    ljmp    task_ret_point              ");
    asm("                                               ");
    asm("   endm                                        ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Save context with clearing bReady and setting bCanContinue           */
/************************************************************************/
    asm("_call_OS_ClearReadySetCanContinue      macro   ");
    asm("                                               ");
    asm("   local   task_ret_point, label2              ");
    asm("   global  OS_ClearReadySetCanContinue         ");
    asm("                                               ");
    asm("   dw      0xC00 | low(label2)                 ");
    asm("   ljmp    OS_ClearReadySetCanContinue         ");
    asm("task_ret_point:                                ");
    asm("   psect   os_pic12_jmp_table                  ");
    asm("label2:    ljmp    task_ret_point              ");
    asm("                                               ");
    asm("   endm                                        ");

//------------------------------------------------------------------------------





//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR OLD STYLE STATIC TIMERS WORK
 *
 ******************************************************************************************/

#define __OS_Timer8Work(TIMER_ID,L)                                                             \
{                                                                                               \
    if ((OS_Timeouts[(TIMER_ID)>>3]&(1<<((TIMER_ID)&7)))) {                                     \
        if (!++OS_Timers8[TIMER_ID])                                                            \
            OS_Timeouts[(TIMER_ID)>>3]&=~(1<<((TIMER_ID)&7));                                   \
    }                                                                                           \
}


#define __OS_Timer16Work(TIMER_ID,L)                                                            \
{                                                                                               \
    if ((OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER16_POS)&7))))       \
    if (!++*((OS_TIMERS16_BANK char*)&OS_Timers16[TIMER_ID]+0)) {                               \
        if (!++*((OS_TIMERS16_BANK char*)&OS_Timers16[TIMER_ID]+1)) {                           \
            OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER16_POS)&7));   \
        };                                                                                      \
    };                                                                                          \
}


#define __OS_Timer24Work(TIMER_ID,L)                                                            \
{                                                                                               \
    if ((OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER24_POS)&7))))       \
    if (!++*((OS_TIMERS24_BANK char*)&OS_Timers24[TIMER_ID]+0)) {                               \
        if (!++*((OS_TIMERS24_BANK char*)&OS_Timers24[TIMER_ID]+1)) {                           \
            OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER24_POS)&7));   \
        };                                                                                      \
    };                                                                                          \
}



#define __OS_Timer32Work(TIMER_ID,L)                                                            \
    if ((OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER32_POS)&7))))       \
    if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+0)) {                               \
        if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+1)) {                           \
            if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+2)) {                       \
                if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+3)) {                   \
                    OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3] &=                               \
                        ~(1<<((TIMER_ID+_OS_TIMER32_POS)&7));                                   \
                };                                                                              \
            };                                                                                  \
        };                                                                                      \
    };                                                                                          \





/******************************************************************************************
 *
 * MACROS FOR WORK WITH TASK TIMERS
 *
 ******************************************************************************************/


#define ASM_OST_TCB_SIZE_CONST  asm(" ");
#define ASM_SET_BANK            asm(" ");


//------------------------------------------------------------------------------
#if   OS_TTIMER_SIZE == 1
//------------------------------------------------------------------------------

    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay) {                                            \
                if (!++OS_TaskVars[TASK_ID].Timer)                                              \
                    OS_TaskVars[TASK_ID].State.bDelay = 0;                                      \
            }                                                                                   \
        }

//------------------------------------------------------------------------------
#elif OS_TTIMER_SIZE == 2
//------------------------------------------------------------------------------

    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay)                                              \
            if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+0)) {                     \
                if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+1)) {                 \
                    OS_TaskVars[TASK_ID].State.bDelay = 0;                                      \
                }                                                                               \
            }                                                                                   \
        }

//------------------------------------------------------------------------------
#elif OS_TTIMER_SIZE == 4
//------------------------------------------------------------------------------

    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay)                                              \
            if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+0)) {                     \
                if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+1)) {                 \
                    if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+2)) {             \
                        if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+3)) {         \
                            OS_TaskVars[TASK_ID].State.bDelay = 0;                              \
                        }                                                                       \
                    }                                                                           \
                }                                                                               \
            }                                                                                   \
        }

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
/******************************************************************************************/












/******************************************************************************************
 *
 *  WORK WITH DYNAMIC TIMERS
 *
 ******************************************************************************************/


//------------------------------------------------------------------------------
#ifdef OS_ENABLE_DTIMERS
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
#if   OS_DTIMER_SIZE == 1
//------------------------------------------------------------------------------

    #define OS_INC_DTIMER()                                 \
        {                                                   \
            /* Now W = fsr */                               \
            asm("   incf    __fsr, f    ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   bcf     __status, 2 ");                 \
            asm("   incf    __indf, f   ");                 \
            asm("   movwf   __fsr       ");                 \
            if (_status & 4) _indf |= 1;                    \
        }

//------------------------------------------------------------------------------
#elif OS_DTIMER_SIZE == 2
//------------------------------------------------------------------------------

    #define OS_INC_DTIMER()                                 \
        {                                                   \
            asm("   bcf     __status, 0 ");                 \
            /* Now W = fsr */                               \
            asm("   incf    __fsr, f    ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   incfsz  __indf, f   ");                 \
            asm("   goto    $ + 5       ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   incfsz  __indf, f   ");                 \
            asm("   goto    $ + 2       ");                 \
            asm("   bsf     __status, 0 ");                 \
            asm("   movwf   __fsr       ");                 \
            if (_status & 1) _indf |= 1;                    \
        }

//------------------------------------------------------------------------------
#elif OS_DTIMER_SIZE == 4
//------------------------------------------------------------------------------

    #define OS_INC_DTIMER()                                 \
        {                                                   \
            asm("   bcf     __status, 0 ");                 \
            /* Now W = fsr */                               \
            asm("   incf    __fsr, f    ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   incfsz  __indf, f   ");                 \
            asm("   goto    $ + 11      ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   incfsz  __indf, f   ");                 \
            asm("   goto    $ + 8       ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   incfsz  __indf, f   ");                 \
            asm("   goto    $ + 5       ");                 \
            asm("   incf    __fsr, f    ");                 \
            asm("   incfsz  __indf, f   ");                 \
            asm("   goto    $ + 2       ");                 \
            asm("   bsf     __status, 0 ");                 \
            asm("   movwf   __fsr       ");                 \
            if (_status & 1) _indf |= 1;                    \
        }

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------


#define __OS_DTimersWork()                                  \
    {                                                       \
        _fsr = (_FSR_TYPE) &_OS_DTimers;                    \
                                                            \
        /* Avoid to use CheckIndfReady because of FSR */    \
        /* can be cleared                             */    \
                                                            \
        while (_indf & 8)               /* bEnable */       \
        {                                                   \
            _fsr++;                                         \
            _fsr = _indf;                                   \
            if (!(_indf & 4)) continue; /* Run      */      \
            OS_INC_DTIMER();                                \
        }                                                   \
    }


//------------------------------------------------------------------------------
#endif  // OS_ENABLE_DTIMER
//------------------------------------------------------------------------------




/******************************************************************************************
 *
 *
 *
 ******************************************************************************************/


#endif















